home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / pascal / zipper.com / ZIPPER.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1989-05-02  |  10.2 KB  |  484 lines

  1.  
  2.  
  3. {*****************************************************************************
  4.  
  5.    ZIPPER.PAS/TPU, overly simplified routines for manipulating central
  6.    directory entrys within ZIP files.
  7.  
  8.    All routines public domain May 2, 1989, written by Tom Guinther except
  9.    for SeekLong() which was kludged by Tom Guinther.
  10.  
  11. *****************************************************************************}
  12.  
  13.  
  14.  
  15.  
  16. {$I-}
  17.  
  18. Unit Zipper;
  19.  
  20.  
  21. Interface
  22.  
  23.  
  24. {$IFDEF EXTRA}
  25. Uses
  26.  TpString;
  27.  
  28.  
  29.  
  30. Const
  31.  
  32.   BufSize = $0400; { 1k, This const is used by SeekLong }
  33.  
  34.  
  35. { Types used by SeekLong }
  36.  
  37. Type
  38.  
  39.   pBufferType = ^BufferType;
  40.   BufferType  = Array[1..BufSize] of Byte;
  41.  
  42. {$ENDIF}
  43.  
  44.  
  45.  
  46. Const
  47.  
  48.   _LOCALFILESIG_      = $04034b50;
  49.   _CENTRALDIRSIG_     = $02014b50;
  50.   _ENDCENTRALDIRSIG_  = $06054b50;
  51.  
  52.  
  53.  
  54. Type
  55.  
  56.   zFile = File;   { Untype }
  57.  
  58.  
  59.   pCentralDir = ^CentralDirRec;
  60.   pZipDir     = ^ZipDirRec;
  61.  
  62.  
  63.   GeneralInfo = Record   { Information common to local/central entrys }
  64.  
  65.            VersionToExtract,
  66.            GPBiteFlag,
  67.            CompMethod,
  68.            FTime,
  69.            FDate               : Word;
  70.  
  71.            CRC_32,
  72.            CompSize,
  73.            UnCompSize          : LongInt;
  74.  
  75.            FnameLen,
  76.            ExFieldLen          : Word;
  77.  
  78.  
  79.  
  80.   End;
  81.  
  82.  
  83.   LocalFileRec  = Record
  84.  
  85.             Signature : LongInt;
  86.             FileInfo  : GeneralInfo;
  87.  
  88.   End;
  89.  
  90.  
  91.   CentralDirRec = Record
  92.  
  93.            Signature           : LongInt;
  94.            VersionMadeBy       : Word;        { Not included in genral info! }
  95.  
  96.            FileInfo            : GeneralInfo;
  97.  
  98.            FcommentLen         : Word;
  99.  
  100.            DiskNumStart,
  101.            InternalFAttr       : Word;
  102.            ExternalFAttr       : LongInt;
  103.  
  104.            RelOfsLocalHdr      : LongInt;
  105.  
  106.   End;
  107.  
  108.  
  109.   ZipDirRec = Record
  110.  
  111.         pCD      : pCentralDir;
  112.         pVar     : Pointer;
  113.         pVarSize : LongInt;
  114.  
  115.   End;
  116.  
  117.  
  118.  
  119. Function  FindCentralDirectory(Var F : zFile) : LongInt;
  120. Function  OpenZip(VAR F : zFile; Name : String) : Boolean;
  121. Function  ReadCentralDirEntry(Var F : zFile; pZip : pZipDir ) : Boolean;
  122. Procedure FreeZipRec(pZ : pZipDir);
  123. Function  MakeFileName(pZ : pZipDir) : String;
  124.  
  125.  
  126. Implementation
  127.  
  128.  
  129. {$F+}
  130. Function HeapFunc(Size : Word) : Integer;
  131. Begin
  132.  
  133.   HeapFunc := 1;
  134.  
  135. End;
  136. {$F-}
  137.  
  138.  
  139.  
  140. Function GetMemCheck(var P; Bytes : Word) : Boolean;
  141. Var
  142.   SaveHeapError : Pointer;
  143.   Pt            : Pointer absolute P;
  144.  
  145. Begin
  146.  
  147.   SaveHeapError := HeapError; { Take over heap error control }
  148.   HeapError     := @HeapFunc;
  149.  
  150.   GetMem(Pt, Bytes);
  151.   GetMemCheck   := (Pt <> nil);
  152.  
  153.   HeapError := SaveHeapError; { Restore heap error control   }
  154.  
  155. End;
  156.  
  157.  
  158.  
  159. { Avoid freeing a NIL pointer }
  160.  
  161. Procedure FreeMemCheck(P : Pointer; Size : Word);
  162. Begin
  163.  
  164.      If P <> NIL Then
  165.        FreeMem(P,Size);
  166.  
  167. End;
  168.  
  169.  
  170.  
  171. {*****************************************************************************
  172.  
  173.   SeekCentralDir:
  174.  
  175.     This function scans a ZIP file looking for the central directory.
  176.  
  177.     It assumes that a series of local file headers/files precedes the
  178.     central directory. It uses the information contained in the local
  179.     file header to move the file pointer past the actual file contents.
  180.     This speeds up the I/O processing immensely.
  181.  
  182. *****************************************************************************}
  183.  
  184. Function SeekCentralDir(VAR F : zFile) : Boolean;
  185. Var
  186.  CurPos  : LongInt;
  187.  Buf     : LocalFileRec;
  188.  IOError : Integer;
  189.  Result  : word;
  190.  
  191. Begin
  192.  
  193.         SeekCentralDir := False;
  194.  
  195.         CurPos := 0;
  196.         Seek(F,0);
  197.  
  198.         BlockRead(F,Buf,SizeOf(LocalFileRec),Result);
  199.  
  200.         IOError := IOResult;
  201.  
  202.         While (IOError = 0) and (Buf.Signature = _LOCALFILESIG_) Do
  203.         Begin
  204.  
  205.  
  206.             With Buf, FileInfo Do
  207.               CurPos := FilePos(F)+FNameLen+ExFieldLen+CompSize;
  208.  
  209.             Seek(F,CurPos);
  210.  
  211.             BlockRead(F,Buf,SizeOf(LocalFileRec),Result);
  212.  
  213.             IOError := IOResult;
  214.  
  215.         End;
  216.  
  217.         If IOError <> 0 Then
  218.           Exit;
  219.  
  220.         If (Buf.Signature = _CENTRALDIRSIG_) Then
  221.         Begin
  222.  
  223.             SeekCentralDir := True;
  224.             Seek(F,CurPos);          { Rewind back size of local header }
  225.  
  226.         End;
  227.  
  228. End;
  229.  
  230.  
  231. {$IFDEF EXTRA}
  232.  
  233. {****************************************************************************
  234.  
  235.    SeekLong:  This function attempts to find a long integer within the
  236.               file F. A buffer of BufSize is used to speed up I/O
  237.               operations. The last 3 bytes of the I/O buffer *must* be
  238.               saved (they couldn't be compared since the length of a LongInt
  239.               is > 3 bytes). This means that all reads after the initial read
  240.               are of the size bufSize-3.
  241.  
  242.               This function uses the Search Function from Turbo Professional
  243.               4/5, but you could easily replace it with one of your own.
  244.  
  245.  
  246. ******************************************************************************}
  247.  
  248. Function SeekLong(VAR F : zFile; L : LongInt) : Boolean;
  249. Var
  250.   Buf    : pBufferType;
  251.   Result : Word;
  252.   Ofs1   : LongInt;
  253.   OfsX   : Word;
  254.   Done   : Boolean;
  255.  
  256. Begin
  257.  
  258.         SeekLong := False;
  259.         Done     := False;
  260.         Ofs1     := 0;
  261.  
  262.         If NOT GetMemCheck(Buf,SizeOf(BufferType)) Then
  263.            Exit;
  264.  
  265.     Blockread(F,Buf^,BufSize,result);  { initial read }
  266.  
  267.         If (IoResult <> 0) Then
  268.          Done := True;
  269.  
  270.     while NOT Done Do
  271.         Begin
  272.  
  273.             OfsX := Search(Buf^,BufSize,L,SizeOf(LongInt));
  274.  
  275.             If OfsX = $FFFF Then
  276.             Begin
  277.  
  278.                Ofs1 := Ofs1 + BufSize-3;
  279.                Move(Buf^[BufSize-3],Buf^[1],3);
  280.  
  281.                If Eof(F) Then
  282.                  Done := True
  283.                Else
  284.                Begin
  285.  
  286.                  BlockRead(F,Buf^[4],BufSize-3,Result);
  287.  
  288.                  If IoResult <> 0 Then
  289.                    Done := True;
  290.  
  291.                End
  292.  
  293.             End
  294.             Else
  295.             Begin
  296.  
  297.               Done     := True;
  298.               SeekLong := True;
  299.               Ofs1     := Ofs1 + OfsX;
  300.  
  301.               Seek(F,Ofs1);   { Rewind back to where we found L }
  302.  
  303.             End;
  304.  
  305.         End;
  306.  
  307.         FreeMemCheck(Buf,BufSize);
  308.  
  309. End;
  310.  
  311. {$ENDIF}
  312.  
  313.  
  314.  
  315. {*****************************************************************************
  316.  
  317.   FindCentralDirectory:
  318.  
  319.    This function uses SeekCentralDir to position the file pointer to the
  320.    start of the central directory. If the central Directory is not found
  321.    it returns 0, otherwise it returns the offset of the central directory.
  322.  
  323. *****************************************************************************}
  324.  
  325. Function FindCentralDirectory(Var F : zFile) : LongInt;
  326. Begin
  327.  
  328.        If SeekCentralDir(F) Then
  329.             FindCentralDirectory := FilePos(F)
  330.        Else
  331.             FindCentralDirectory := 0;
  332.  
  333. End;
  334.  
  335.  
  336.  
  337. {*****************************************************************************
  338.  
  339.   OpenZip: This routine opens F (a zFile, untyped) with a record size of 1.
  340.            F is opened in read/only mode. This function returns false if
  341.            it cannot open the file.
  342.  
  343. *****************************************************************************}
  344.  
  345. Function OpenZip(VAR F : zFile; Name : String) : Boolean;
  346. Begin
  347.  
  348.         Assign(F,Name);
  349.  
  350.         If IoResult <> 0 Then
  351.           Exit;
  352.  
  353.         Reset(F,1);
  354.  
  355.         Openzip := IoResult = 0;
  356.  
  357. End;
  358.  
  359.  
  360.  
  361. {*****************************************************************************
  362.  
  363.   ReadCentralDirectory:
  364.  
  365.    This function reads the current central directory entry, allocating
  366.    memory for the data structures. Each directory entry has a variable
  367.    length data area, which makes it almost impossible to use a static
  368.    data structure to hold an entry. This routine will return false if
  369.    an I/O error occurs or it cannot allocate enough memory to hold the
  370.    data.
  371.  
  372. *****************************************************************************}
  373.  
  374. Function ReadCentralDirEntry(Var F : zFile; pZip : pZipDir ) : Boolean;
  375. Var
  376.   Result : Word;
  377.   VSize  : LongInt;
  378.   Vptr   : Pointer;
  379.   pL     : Pointer;
  380.  
  381. Begin
  382.  
  383.         ReadCentralDirEntry := False;
  384.  
  385.         If NOT GetMemCheck(pZip^.pCD,SizeOf(CentralDirRec)) Then
  386.             Exit;
  387.  
  388.         BlockRead(F,pZip^.pCD^,SizeOf(CentralDirRec),Result);
  389.  
  390.         If (IoResult <> 0) or (Result <> SizeOf(CentralDirRec)) Then
  391.            Exit;
  392.  
  393.         pL := pZip^.pCD;
  394.  
  395.         If LongInt(pL^) <> _CENTRALDIRSIG_ Then
  396.           Exit;  { Item is NOT a central directory entry }
  397.  
  398.         With pZip^, pCD^, FileInfo do
  399.         Begin
  400.  
  401.            { Calculate size of variable data area }
  402.  
  403.            VSize := FnameLen + ExFieldLen + FCommentLen;
  404.  
  405.            If NOT GetMemCheck(Vptr,Vsize) Then
  406.              Exit;
  407.  
  408.            BlockRead(F,Vptr^,Vsize,Result);
  409.  
  410.            If (IoResult <> 0) or (Result <> Vsize) Then
  411.              Exit;
  412.  
  413.            pZip^.pVar     := Vptr;
  414.            pZip^.pVarSize := VSize;
  415.  
  416.         End;
  417.  
  418.         ReadCentralDirEntry := True;
  419.  
  420. End;
  421.  
  422.  
  423.  
  424. {*****************************************************************************
  425.  
  426.    FreeZipRec: This function will free a dynamically allocated central
  427.                directory entry.
  428.  
  429.  
  430. *****************************************************************************}
  431.  
  432. Procedure FreeZipRec(pZ : pZipDir);
  433. Begin
  434.  
  435.      If pZ = NIL Then Exit;
  436.  
  437.      With pZ^ Do
  438.      Begin
  439.  
  440.           { Free the central directory record }
  441.  
  442.           FreeMemCheck(pCD,SizeOf(CentralDirRec));
  443.  
  444.           { Free The variable length field(s) }
  445.  
  446.           FreeMemCheck(pVar,SizeOf(pVarSize));
  447.  
  448.      End;
  449.  
  450. End;
  451.  
  452.  
  453.  
  454. {*****************************************************************************
  455.  
  456.    MakeFileName:
  457.  
  458.       This function converts a central directory file name into an LString.
  459.  
  460. *****************************************************************************}
  461.  
  462. Function MakeFileName(pZ : pZipDir) : String;
  463. Var
  464.   Tmp : String;
  465.  
  466. Begin
  467.  
  468.    With pZ^, pCD^, FileInfo Do
  469.    Begin
  470.  
  471.      Tmp[0] := Char(ShortInt(FileInfo.FnameLen));
  472.  
  473.      Move(pVar^,Tmp[1],FileInfo.FnameLen);
  474.  
  475.    End;
  476.  
  477.    MakeFileName := Tmp;
  478.  
  479. End;
  480.  
  481.  
  482.  
  483. End.  { Implementation }
  484.